package com.google.gwt.it2tool.server;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;

import com.google.appengine.api.datastore.DatastoreNeedIndexException;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.it2tool.client.CustomFactoryOrder;
import com.google.gwt.it2tool.client.Factory;
import com.google.gwt.it2tool.client.NotLoggedInException;
import com.google.gwt.it2tool.client.Production;
import com.google.gwt.it2tool.client.ProductionPrototype;
import com.google.gwt.it2tool.client.Recipe;

public class DataStorageAdapter {

	private static final Logger LOG = Logger.getLogger(FactoryServiceImpl.class.getName());
	private static final PersistenceManagerFactory PMF =
		JDOHelper.getPersistenceManagerFactory("transactions-optional");

	public void addFactory(Factory factory){
		FactoryJDO factoryJDO = getFactoryJDO(factory); 
		if (factoryJDO==null){
			factoryJDO = new FactoryJDO(factory,getUser());
		}else{
			factoryJDO.set(factory);
			factoryJDO.setUser(getUser());
		}
		PersistenceManager pm = getPersistenceManager();
		try {
			pm.makePersistent(factoryJDO);
		} finally {
			pm.close();
		}
	}

	@SuppressWarnings("unchecked")
	private FactoryJDO getFactoryJDO(Factory fac){
		PersistenceManager pm = getPersistenceManager();
		try {
			Query q = pm.newQuery(FactoryJDO.class, "user==u && id==i");
			q.declareParameters("com.google.appengine.api.users.User u, String i");
			List<FactoryJDO> factories = (List<FactoryJDO>) q.execute(getUser(),fac.getId());
			if(factories!=null && !factories.isEmpty()){
				return factories.get(0);
			}
			else return null;
		} finally {
			pm.close();
		} 
	}

	public void removeFactory(Factory factory) throws NotLoggedInException {
		PersistenceManager pm = getPersistenceManager();
		try {		  
			Query q = pm.newQuery(FactoryJDO.class, "id==i");
			q.declareParameters("String i");
			q.deletePersistentAll(factory.getId());		  
		} finally {
			pm.close();
		}
	}

	public List<Factory> getSortedFactories(){
		return getFactories(true);
	}
	
	private List<Factory> getUnsortedFactories(){
		return getFactories(false);
	}
	
	@SuppressWarnings("unchecked")
	public List<Factory> getFactories(boolean sorted){
		PersistenceManager pm = getPersistenceManager();
		ArrayList<Factory> output = new ArrayList<Factory>();
		try {
			Query q = pm.newQuery(FactoryJDO.class, "user == u");
			if(sorted){
				q.setOrdering("id asc");
			}
			q.declareParameters("com.google.appengine.api.users.User u");
			List<FactoryJDO> factories = (List<FactoryJDO>) q.execute(getUser());
			for (FactoryJDO fac : factories) {
				ArrayList<Production> prods_client = new ArrayList<Production>();
				ArrayList<ProductionJDO> prods_server = fac.getProductions();
				int size = prods_server.size();
				ProductionJDO curr;
				for (int i=0;i<size;i++){
					curr=prods_server.get(i);
					prods_client.add(new Production(curr.getId(),curr.getName(), curr.getArea(), curr.getProductivity(), curr.getDuration()));
				}
				output.add(new Factory(fac.getName(),fac.getId(),prods_client));
			}
		}catch (DatastoreNeedIndexException e) {
			return getUnsortedFactories();
		}
		finally {
			pm.close();
		}
		return output;
	}
	
	public void addProduction(Production prod){
		PersistenceManager pm = getPersistenceManager();
		try {
			//Check if alread existing in DB
			ProductionJDO p = getProduction(prod, pm, false);
			if(p!=null){
				p.set(prod);
			}else{
				//Insert new Production
				p = new ProductionJDO(prod);
				pm.makePersistent(p);				
			}
		} finally {
			pm.close();
		}
	}

	public void removeProduction(Production prod){
		PersistenceManager pm = getPersistenceManager();
		try {		  
			Query q = pm.newQuery(ProductionJDO.class, "id==i");
			q.declareParameters("String i");
			q.deletePersistentAll(prod.getId());		  
		} finally {
			pm.close();
		}
	}
	
	public ProductionJDO getProduction(Production prod){
		PersistenceManager pm = getPersistenceManager();		
		return getProduction(prod, pm, true);
		
	}
	
	@SuppressWarnings("unchecked")
	private ProductionJDO getProduction(Production prod, PersistenceManager pm, boolean closePm){
		try {
			Query q = pm.newQuery(ProductionJDO.class, "id==i");
			q.declareParameters("String i");
			List<ProductionJDO> prods = (List<ProductionJDO>) q.execute(prod.getId());
			if(prods!=null && !prods.isEmpty()){
				return prods.get(0);
			}
			else return null;
		} finally {
			if(closePm){
				pm.close();
			}
		}
	}
	
	public void storeMassProductionLvl(int lvl){
		PersistenceManager pm = getPersistenceManager();
		try {
			//Check if alread existing in DB
			MassProductionLvlJDO p = getMassProductionLvl(pm, false);
			if(p!=null){
				p.setLvl(lvl);
			}else{
				//Insert new Production
				p = new MassProductionLvlJDO(lvl,getUser());
				pm.makePersistent(p);				
			}
		} finally {
			pm.close();
		}
	}
	
	public Integer getMassProductionLvl(){
		PersistenceManager pm = getPersistenceManager();
		MassProductionLvlJDO p = getMassProductionLvl(pm, true);
		if (p!=null){
			return p.getLvl();
		}else{
			return 0;
		}
	}
	
	@SuppressWarnings("unchecked")
	private MassProductionLvlJDO getMassProductionLvl(PersistenceManager pm, boolean closePm){
		try {
			Query q = pm.newQuery(MassProductionLvlJDO.class, "user==u");
			q.declareParameters("com.google.appengine.api.users.User u");
			List<MassProductionLvlJDO> prods = (List<MassProductionLvlJDO>) q.execute(getUser());
			if(prods!=null && !prods.isEmpty()){
				return prods.get(0);
			}
			else return null;
		} finally {
			if(closePm){
				pm.close();
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<Recipe> getRecipies(){
		List<Recipe> output = new ArrayList<Recipe>();
		PersistenceManager pm = getPersistenceManager();
		try {
			Query q = pm.newQuery(RecipeJDO.class);
			List<RecipeJDO> recipes = (List<RecipeJDO>) q.execute();
			for (RecipeJDO r : recipes) {
				output.add(new Recipe(r.getName(),r.getIngridientsAsHashmap(),r.getUnitsAsHashmap()));
			}
			return output;
		} finally {			
			pm.close();			
		}
	}
	
	public void storeRecipe(Recipe reci){
		PersistenceManager pm = getPersistenceManager();
		try {
			//Check if alread existing in DB
			RecipeJDO r = getRecipe(reci.getName(), pm, false);
			if(r!=null){
				r.setIngridients(reci.getIngridients(),reci.getUnits());
			}else{
				//Insert new Production
				r = new RecipeJDO(reci.getName(),reci.getIngridients(),reci.getUnits());
				pm.makePersistent(r);				
			}
		} finally {
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	private RecipeJDO getRecipe(String name, PersistenceManager pm, boolean closePm){
		try {
			Query q = pm.newQuery(RecipeJDO.class, "name==n");
			q.declareParameters("String n");
			List<RecipeJDO> recs = (List<RecipeJDO>) q.execute(name);
			if(recs!=null && !recs.isEmpty()){
				return recs.get(0);
			}
			else return null;
		} finally {
			if(closePm){
				pm.close();
			}
		}
	}
	
	public void storeProductionPrototype(ProductionPrototype proto){
		PersistenceManager pm = getPersistenceManager();
		try {
			//Check if alread existing in DB
			ProductionPrototypeJDO p = getProductionPrototype(proto.getName(), pm, false);
			if(p!=null){
				p.set(proto);
			}else{
				//Insert new Production
				p = new ProductionPrototypeJDO(proto);
				pm.makePersistent(p);				
			}
		} finally {
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<ProductionPrototype> getProductionPrototypes(){
		List<ProductionPrototype> output = new ArrayList<ProductionPrototype>();
		PersistenceManager pm = getPersistenceManager();
		try {
			Query q = pm.newQuery(ProductionPrototypeJDO.class);
			List<ProductionPrototypeJDO> protos = (List<ProductionPrototypeJDO>) q.execute();
			for (ProductionPrototypeJDO p : protos) {
				output.add(new ProductionPrototype(p.getName(),p.getProductivity(),p.getDuration()));
			}
			return output;
		} finally {			
			pm.close();			
		}
	}
	
	public ProductionPrototype getProductionPrototype(String name){
		PersistenceManager pm = getPersistenceManager();
		ProductionPrototypeJDO pJDO = getProductionPrototype(name, pm, true);
		return new ProductionPrototype(pJDO.getName(), pJDO.getProductivity(), pJDO.getDuration());
	}
	
	@SuppressWarnings("unchecked")
	private ProductionPrototypeJDO getProductionPrototype(String name, PersistenceManager pm, boolean closePm){
		try {
			Query q = pm.newQuery(ProductionPrototypeJDO.class, "name==n");
			q.declareParameters("String n");
			List<ProductionPrototypeJDO> recs = (List<ProductionPrototypeJDO>) q.execute(name);
			if(recs!=null && !recs.isEmpty()){
				return recs.get(0);
			}
			else return null;
		} finally {
			if(closePm){
				pm.close();
			}
		}
	}
	
	public void storeCustomFactoryOrder(CustomFactoryOrder order){
		PersistenceManager pm = getPersistenceManager();
		try {
			//Check if alread existing in DB
			CustomFactoryOrderJDO o = getCustomFactoryOrder(pm, false);
			if(o!=null){
				o.set(order);
			}else{
				//Insert new Production
				o = new CustomFactoryOrderJDO(order.getOrder());
				o.setUser(getUser());
				pm.makePersistent(o);				
			}
		} finally {
			pm.close();
		}
	}
	
	public CustomFactoryOrder getCustomFactoryOrder(){
		PersistenceManager pm = getPersistenceManager();
		CustomFactoryOrderJDO oJDO = getCustomFactoryOrder(pm, true);
		if (oJDO==null){
			return new CustomFactoryOrder();
		}else{
			return new CustomFactoryOrder(oJDO.getOrder());	
		}
		
	}
	
	@SuppressWarnings("unchecked")
	private CustomFactoryOrderJDO getCustomFactoryOrder(PersistenceManager pm, boolean closePm){
		try {
			Query q = pm.newQuery(CustomFactoryOrderJDO.class, "user==u");
			q.declareParameters("com.google.appengine.api.users.User u");
			List<CustomFactoryOrderJDO> recs = (List<CustomFactoryOrderJDO>) q.execute(getUser());
			if(recs!=null && !recs.isEmpty()){
				return recs.get(0);
			}
			else return null;
		} finally {
			if(closePm){
				pm.close();
			}
		}
	}

	private User getUser() {
		UserService userService = UserServiceFactory.getUserService();
		return userService.getCurrentUser();
	}

	private PersistenceManager getPersistenceManager() {
		return PMF.getPersistenceManager();
	}
}
